use rocket::{Request, response};
use rocket::request::{FromRequest, Outcome};
use rocket::response::Responder;
use rocket::serde::json::Json;
use serde::Serialize;
use sqlx::Error;

#[derive(Serialize)]
pub struct Res<T: Serialize> {
    pub code: i32,
    pub msg: String,
    pub data: Option<T>,
}

impl<T: Serialize> Res<T> {
    pub fn ok(data: T) -> Self {
        Res { code: 0, msg: String::from("success"), data: Some(data) }
    }
    pub fn ok_nil() -> Self {
        Res { code: 0, msg: String::from("success"), data: None }
    }

    pub fn failure_str(msg: &str) -> Self {
        Res { code: -1, msg: String::from(msg), data: None }
    }

    pub fn failure(msg: String) -> Self {
        Res { code: -1, msg, data: None }
    }
}

impl<'r, 'o: 'r, T: Serialize> Responder<'r, 'o> for Res<T> {
    fn respond_to(self, req: &'r Request<'_>) -> response::Result<'o> {
        Json(serde_json::json!(self)).respond_to(req)
    }
}


pub(crate) trait ToResult<T: Serialize> {
    fn to_res(self) -> Res<T>;
}

impl<T: Serialize> ToResult<T> for Result<T, Error> {
    fn to_res(self) -> Res<T> {
        match self {
            Ok(v) => Res::ok(v),
            Err(e) => Res::failure(e.to_string())
        }
    }
}


pub struct Paging {
    pub size: i32,
    pub no: i32,
}
#[rocket::async_trait]
impl<'r> FromRequest<'r> for  Paging
{
    type Error = std::convert::Infallible;

    async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
        let size = request.query_value::<i32>("size")
            .unwrap_or_else(|| Ok(10))
            .unwrap_or(10); // provide a default value in case of None
        let no = request.query_value::<i32>("no")
            .unwrap_or_else(|| Ok(1))
            .unwrap_or(1) - 1;
        Outcome::Success(Paging{ size,no})
    }
}